Skip to content

feat(clerk-js): Introduce navigate for setActive #6486

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 45 commits into from
Aug 13, 2025

Conversation

LauraBeatris
Copy link
Member

@LauraBeatris LauraBeatris commented Aug 7, 2025

Description

This PR introduces a new API to navigate on setActive, that can be leveraged for after-auth flows to handle pending sessions, featuring a callback mechanism that enables developers to integrate their application logic, such as navigation.

Previously, our flows were mistakenly navigating after setActive, which could cause issues with session revalidation and re-render of pages.

From now on, we're proposing two options to deal with after-auth: taskUrls or navigate

navigate

A callback function that can be provided as an setActive option.

setActive({ 
  navigate: async ({ session }) => { 
     const currentTask = session.currentTask; 

     if (currentTask){ 
      // Developer has full control over navigation logic
      // (this also allows our AIO components to pass their navigation context such as modal routing)
       await router.push(`/onboarding/${currentTask.key}`)
       return 
     }

    await router.push('/dashboard')
  }
})

taskUrls (existing)

A map of URLs per session task key that can be provided as a Clerk option. On setActive, it'll be used for navigation.

<ClerkProvider 
   taskUrls={{'choose-organization': '/onboarding/choose-organization' }}
/>

AIOs behavior

CleanShot.2025-08-07.at.22.30.57.mp4

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Added per-task routing APIs (buildTasksUrl, redirectToTasks) and optional navigate callback for setActive; sign-in/sign-up contexts and session-tasks expose navigateOnSetActive and taskUrl; new HOCs to redirect to sign-in/sign-up tasks.
  • Refactor

    • Renamed RedirectToTask→RedirectToTasks and SessionTask→SessionTasks; centralized task-based navigation and removed legacy internal navigate-to-task plumbing.
  • Tests

    • Expanded coverage for pending-session flows, setActive navigation behavior, and task→URL mappings.
  • Chores

    • Updated bundle thresholds and changesets.

@LauraBeatris LauraBeatris self-assigned this Aug 7, 2025
Copy link

changeset-bot bot commented Aug 7, 2025

🦋 Changeset detected

Latest commit: aca655f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
Name Type
@clerk/clerk-js Minor
@clerk/types Minor
@clerk/tanstack-react-start Minor
@clerk/react-router Minor
@clerk/nextjs Minor
@clerk/clerk-react Minor
@clerk/remix Minor
@clerk/vue Minor
@clerk/chrome-extension Patch
@clerk/clerk-expo Patch
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/backend Patch
@clerk/elements Patch
@clerk/expo-passkeys Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/localizations Patch
@clerk/nuxt Patch
@clerk/shared Patch
@clerk/testing Patch
@clerk/themes Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

vercel bot commented Aug 7, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Ready Preview Comment Aug 13, 2025 8:11pm

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🔭 Outside diff range comments (1)
packages/clerk-js/src/core/clerk.ts (1)

1201-1220: Avoid unsafe cast when resolving session by ID

Blindly asserting the found session to SignedInSessionResource can hide bugs and accidentally sign users out when an invalid session ID is passed. Fail fast with a clear error instead.

Apply this diff:

-      if (typeof session === 'string') {
-        session = (this.client.sessions.find(x => x.id === session) as SignedInSessionResource) || null;
-      }
+      if (typeof session === 'string') {
+        const foundSession = this.client.sessions.find(x => x.id === session);
+        if (!foundSession) {
+          throw new Error(`setActive: Session with ID "${session}" not found.`);
+        }
+        session = foundSession as SignedInSessionResource;
+      }
♻️ Duplicate comments (15)
packages/clerk-js/src/core/sessionTasks.ts (3)

16-16: Add explicit return type to getTaskEndpoint

Internal or not, exported helpers should declare return types for clarity and to avoid accidental widening.

-export const getTaskEndpoint = (task: SessionTask) => `/tasks/${INTERNAL_SESSION_TASK_ROUTE_BY_KEY[task.key]}`;
+export const getTaskEndpoint = (task: SessionTask): string =>
+  `/tasks/${INTERNAL_SESSION_TASK_ROUTE_BY_KEY[task.key]}`;

21-31: Bug: forwarded params placed outside hash; also missing redirectUrl propagation and explicit return type

Task pages are hash-routed. Passing forwarded params via top-level searchParams leaks them outside the hash. Also, the open item to preserve redirectUrl is not implemented, and the function lacks an explicit return type.

Apply all three fixes:

  • Use hashSearchParams (not searchParams).
  • Accept optional redirectUrl and append it (as redirect_url) to hash params.
  • Add explicit return type.
-export function buildTaskUrl(task: SessionTask, opts: Pick<Parameters<typeof buildURL>[0], 'base'>) {
-  const params = forwardClerkQueryParams();
-
-  return buildURL(
-    {
-      base: opts.base,
-      hashPath: getTaskEndpoint(task),
-      searchParams: params,
-    },
-    { stringify: true },
-  );
-}
+export function buildTaskUrl(
+  task: SessionTask,
+  opts: { base: string; redirectUrl?: string },
+): string {
+  const params = forwardClerkQueryParams();
+  if (opts.redirectUrl) {
+    // keep in the hash to survive SPA hash routing
+    params.set('redirect_url', opts.redirectUrl);
+  }
+  return buildURL(
+    {
+      base: opts.base,
+      hashPath: getTaskEndpoint(task),
+      hashSearchParams: params,
+    },
+    { stringify: true },
+  ) as string;
+}

37-53: Propagate redirectUrl and add explicit return type in navigateIfTaskExists

When a session has a pending task, navigation should preserve the original redirectUrl. The function should also declare its return type.

-export function navigateIfTaskExists(
-  session: SessionResource,
-  {
-    navigate,
-    baseUrl,
-  }: {
-    navigate: (to: string) => Promise<unknown>;
-    baseUrl: string;
-  },
-) {
+export function navigateIfTaskExists(
+  session: SessionResource,
+  {
+    navigate,
+    baseUrl,
+    redirectUrl,
+  }: {
+    navigate: (to: string) => Promise<unknown>;
+    baseUrl: string;
+    redirectUrl?: string;
+  },
+): Promise<unknown> | void {
   const currentTask = session.currentTask;
   if (!currentTask) {
     return;
   }
 
-  return navigate(buildTaskUrl(currentTask, { base: baseUrl }));
+  return navigate(buildTaskUrl(currentTask, { base: baseUrl, redirectUrl }));
 }
packages/clerk-js/src/ui/components/SignUp/index.tsx (1)

5-5: Missing TypeScript path alias configuration

The @/ui/hooks/usePreloadTasks import will fail because tsconfig.json doesn't define a @/* path mapping. Add the required path alias configuration or revert to relative imports.

-import { usePreloadTasks } from '@/ui/hooks/usePreloadTasks';
+import { usePreloadTasks } from '../../hooks/usePreloadTasks';
#!/bin/bash
# Verify that TypeScript path mapping for @/ exists
fd -t f "tsconfig.*\.json$" -x cat {} \; | jq -r '.compilerOptions.paths' 2>/dev/null | grep -q '"@/\*"'
if [ $? -eq 0 ]; then
  echo "Path mapping for @/ exists"
else
  echo "Path mapping for @/ does NOT exist"
fi
packages/clerk-js/src/ui/contexts/components/SignIn.ts (2)

32-34: Update return type and make redirectUrl optional in type definition

The type definition should make redirectUrl optional and use Promise<void> for clarity since the navigation doesn't return meaningful data.

-  navigateOnSetActive: (opts: { session: SessionResource; redirectUrl: string }) => Promise<unknown>;
+  navigateOnSetActive: (opts: { session: SessionResource; redirectUrl?: string }) => Promise<void>;

123-133: navigateOnSetActive should respect provider-level taskUrls configuration

The function doesn't check for custom task URLs from the ClerkProvider configuration. According to the documented precedence rules, provider-level taskUrls should take priority over default task navigation paths.

 const navigateOnSetActive = async ({ session, redirectUrl }: { session: SessionResource; redirectUrl: string }) => {
   const currentTask = session.currentTask;
   if (!currentTask) {
     return navigate(redirectUrl || afterSignInUrl);
   }
 
+  // Check for custom task URL from provider configuration
+  const customTaskUrl = clerk.__internal_getOption('taskUrls')?.[currentTask.key];
+  if (customTaskUrl) {
+    return navigate(customTaskUrl);
+  }
+
   const taskEndpoint = getTaskEndpoint(currentTask);
   const taskNavigationPath = isCombinedFlow ? '/create' + taskEndpoint : taskEndpoint;
 
   return navigate(`/${basePath}${taskNavigationPath}`);
 };
packages/types/src/clerk.ts (3)

123-123: Add comprehensive JSDoc for SetActiveNavigate public API type

This public API type needs documentation explaining its purpose, parameters, and usage. Also refine the return type for better type safety.

-export type SetActiveNavigate = ({ session }: { session: SessionResource }) => Promise<unknown>;
+/**
+ * Callback function invoked by `setActive` just before committing the active session/organization.
+ * Use it to implement custom navigation for pending session tasks.
+ *
+ * When provided, this callback takes precedence over `redirectUrl`.
+ *
+ * @param ctx.session - The session that is about to become active. It may contain a `currentTask`.
+ * @returns Optionally return a promise to allow awaiting asynchronous router operations.
+ *
+ * @example
+ * await clerk.setActive({
+ *   session,
+ *   navigate: async ({ session }) => {
+ *     const task = session.currentTask;
+ *     if (task) {
+ *       await router.push(`/tasks/${task.key}`);
+ *       return;
+ *     }
+ *     await router.push('/dashboard');
+ *   },
+ * });
+ */
+export type SetActiveNavigate = (ctx: { session: SessionResource }) => Promise<void> | void;

678-682: Add JSDoc documentation for buildTasksUrl public API method

This new public API method needs comprehensive documentation.

+  /**
+   * Returns the configured URL where session tasks are mounted, based on the current
+   * session's task and configured taskUrls.
+   * 
+   * @returns The URL for the current session task, or an empty string if no task exists
+   * 
+   * @example
+   * const taskUrl = clerk.buildTasksUrl();
+   * // Returns something like: '/sign-in#/tasks/choose-organization'
+   */
   buildTasksUrl(): string;

770-774: Add JSDoc documentation for redirectToTasks public API method

This new public API method needs comprehensive documentation.

+  /**
+   * Redirects to the configured URL where session tasks are mounted.
+   * Uses the URL generated by `buildTasksUrl()`.
+   * 
+   * @returns A promise that resolves when navigation is complete
+   * 
+   * @example
+   * await clerk.redirectToTasks();
+   * // Navigates to the appropriate task URL for the current session
+   */
   redirectToTasks(): Promise<unknown>;
packages/clerk-js/src/core/__tests__/clerk.test.ts (4)

447-457: Type cast mismatch: using PendingSessionResource in active session test

This test is in the "with active session status" suite but casts to PendingSessionResource. Either move the test to the pending session suite or fix the cast to match the test context.

-await sut.setActive({ session: mockSession as any as PendingSessionResource, navigate });
+await sut.setActive({ session: mockSession as any as ActiveSessionResource, navigate });

547-548: Type cast should be PendingSessionResource, not ActiveSessionResource

The test verifies behavior for pending sessions but incorrectly casts to ActiveSessionResource.

-await sut.setActive({ session: mockSession as any as ActiveSessionResource });
+await sut.setActive({ session: mockSession as any as PendingSessionResource });

560-560: Type cast should be PendingSessionResource for consistency

Same casting issue - the test is for pending session behavior but uses ActiveSessionResource.

-await sut.setActive({ session: mockSession as any as ActiveSessionResource });
+await sut.setActive({ session: mockSession as any as PendingSessionResource });

564-578: Add test coverage for navigate callback precedence and redirectUrl preservation

The test suite should verify:

  1. When both navigate callback and taskUrls are provided, the callback takes precedence
  2. redirectUrl passed to setActive is preserved in the navigation URL

Add these test cases after the existing "navigate to taskUrl option" test:

it('prefers navigate callback over taskUrls when both are provided', async () => {
  mockSession.touch.mockReturnValue(Promise.resolve());
  mockClientFetch.mockReturnValue(Promise.resolve({ signedInSessions: [mockSession] }));
  const navigate = jest.fn();

  const sut = new Clerk(productionPublishableKey);
  sut.navigate = jest.fn();
  await sut.load({
    taskUrls: {
      'choose-organization': '/choose-organization',
    },
  });
  await sut.setActive({ session: mockSession as any as PendingSessionResource, navigate });
  expect(mockSession.touch).toHaveBeenCalled();
  expect(navigate).toHaveBeenCalled();
  expect(sut.navigate).not.toHaveBeenCalled();
});

it('preserves redirectUrl when navigating to taskUrl', async () => {
  mockSession.touch.mockReturnValue(Promise.resolve());
  mockClientFetch.mockReturnValue(Promise.resolve({ signedInSessions: [mockSession] }));

  const sut = new Clerk(productionPublishableKey);
  sut.navigate = jest.fn();
  await sut.load({
    taskUrls: {
      'choose-organization': '/choose-organization',
    },
  });
  await sut.setActive({ 
    session: mockSession as any as PendingSessionResource, 
    redirectUrl: '/dashboard' 
  });
  expect(mockSession.touch).toHaveBeenCalled();
  // Verify the URL includes the redirect parameter
  expect(sut.navigate).toHaveBeenCalledWith(
    expect.stringContaining('redirect_url=/dashboard')
  );
});
packages/clerk-js/src/core/clerk.ts (2)

1851-1873: Preserve redirectUrl and honor provider overrides during OAuth task navigation

Current setActiveNavigate drops redirectUrl and ignores provider-level taskUrls. Build the final URL locally and append redirectUrl to hash or query appropriately.

Apply this diff:

     const signInUrl = params.signInUrl || displayConfig.signInUrl;
     const signUpUrl = params.signUpUrl || displayConfig.signUpUrl;

-    const setActiveNavigate = async ({
-      session,
-      baseUrl,
-      redirectUrl,
-    }: {
-      session: SessionResource;
-      baseUrl: string;
-      redirectUrl: string;
-    }) => {
-      if (!session.currentTask) {
-        await this.navigate(redirectUrl);
-        return;
-      }
-
-      await navigateIfTaskExists(session, {
-        baseUrl,
-        navigate: this.navigate,
-      });
-    };
+    const setActiveNavigate = async ({
+      session,
+      baseUrl,
+      redirectUrl,
+    }: {
+      session: SessionResource;
+      baseUrl: string;
+      redirectUrl: string;
+    }) => {
+      if (!session.currentTask) {
+        await this.navigate(redirectUrl);
+        return;
+      }
+      const customTaskUrl = this.#options.taskUrls?.[session.currentTask.key];
+      let to =
+        customTaskUrl ??
+        (buildURL({ base: baseUrl, hashPath: getTaskEndpoint(session.currentTask) }, { stringify: true }) as string);
+      if (redirectUrl) {
+        const useHash = to.includes('#');
+        const buildOpts: Record<string, unknown> = { base: to };
+        if (useHash) {
+          buildOpts.hashSearchParams = { redirectUrl };
+        } else {
+          buildOpts.searchParams = { redirectUrl };
+        }
+        to = buildURL(buildOpts, { stringify: true }) as string;
+      }
+      await this.navigate(to);
+    };

1310-1337: Fix duplicate navigation, preserve redirectUrl correctly, and guard navigate callback errors

  • Duplicate navigation: redirectUrl is navigated twice (with auth and then without).
  • redirectUrl preservation: always appending as hash params breaks path-based URLs.
  • Consumer callback safety: exceptions from setActive.navigate can skip state restoration.

Apply this diff:

       if (!beforeEmit && (redirectUrl || taskUrl || setActiveNavigate)) {
         await tracker.track(async () => {
           if (!this.client) {
             // Typescript is not happy because since thinks this.client might have changed to undefined because the function is asynchronous.
             return;
           }

           if (newSession?.status !== 'pending') {
             this.#setTransitiveState();
           }

           if (taskUrl) {
-            const taskUrlWithRedirect = redirectUrl
-              ? buildURL({ base: taskUrl, hashSearchParams: { redirectUrl } }, { stringify: true })
-              : taskUrl;
-            await this.navigate(taskUrlWithRedirect);
+            let taskUrlWithRedirect = taskUrl;
+            if (redirectUrl) {
+              const useHash = taskUrl.includes('#');
+              const buildOpts: Record<string, unknown> = { base: taskUrl };
+              if (useHash) {
+                buildOpts.hashSearchParams = { redirectUrl };
+              } else {
+                buildOpts.searchParams = { redirectUrl };
+              }
+              taskUrlWithRedirect = buildURL(buildOpts, { stringify: true }) as string;
+            }
+            await this.navigate(taskUrlWithRedirect);
           } else if (setActiveNavigate && newSession) {
-            await setActiveNavigate({ session: newSession });
+            try {
+              await setActiveNavigate({ session: newSession });
+            } catch (err) {
+              logger.error('Clerk.setActive navigate callback failed', err);
+            }
           } else if (redirectUrl) {
-            if (this.client.isEligibleForTouch()) {
+            if (this.client.isEligibleForTouch()) {
               const absoluteRedirectUrl = new URL(redirectUrl, window.location.href);
               const redirectUrlWithAuth = this.buildUrlWithAuth(
                 this.client.buildTouchUrl({ redirectUrl: absoluteRedirectUrl }),
               );
               await this.navigate(redirectUrlWithAuth);
-            }
-            await this.navigate(redirectUrl);
+            } else {
+              await this.navigate(redirectUrl);
+            }
           }
         });
       }
🧹 Nitpick comments (9)
packages/clerk-js/src/core/sessionTasks.ts (3)

9-11: Tighten the mapping type with satisfies (safer than assertion)

Avoids unnecessary assertion and ensures future task keys must be added.

-export const INTERNAL_SESSION_TASK_ROUTE_BY_KEY: Record<SessionTask['key'], string> = {
-  'choose-organization': 'choose-organization',
-} as const;
+export const INTERNAL_SESSION_TASK_ROUTE_BY_KEY = {
+  'choose-organization': 'choose-organization',
+} satisfies Record<SessionTask['key'], string>;

55-69: Type the function return as void for clarity

Minor: make the intent explicit and align with TS best practices for exported helpers.

-export function warnMissingPendingTaskHandlers(options: Record<string, unknown>) {
+export function warnMissingPendingTaskHandlers(options: Record<string, unknown>): void {
   const taskOptions = ['taskUrls', 'navigate'] as Array<
     keyof (Pick<SetActiveParams, 'navigate'> & Pick<ClerkOptions, 'taskUrls'>)
   >;

21-31: Add tests to cover redirectUrl preservation and hash param placement

Please add unit tests that assert:

  • buildTaskUrl returns URLs with forwardClerkQueryParams and redirect_url inside the hash, not top-level query.
  • navigateIfTaskExists preserves redirectUrl when provided.

Do you want me to scaffold these tests (Jest + URL parsing assertions) for sessionTasks?

Also applies to: 37-53

packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx (1)

56-59: Improve error handling consistency

Catching and directly rejecting loses localized error handling. Use the existing handleError + translateError mechanisms used in other UI components to surface errors consistently.

For example: call handleError(err) and/or pass errors back through VerificationCodeCard controls rather than raw reject().

packages/clerk-js/src/ui/contexts/components/SignIn.ts (1)

123-133: Consider making redirectUrl optional and memoizing the callback

The redirectUrl parameter should be optional since it may not always be provided to setActive. Additionally, memoizing the callback would prevent unnecessary re-renders in consuming components.

+import { createContext, useContext, useMemo, useCallback } from 'react';
// ... existing imports

-const navigateOnSetActive = async ({ session, redirectUrl }: { session: SessionResource; redirectUrl: string }) => {
+const navigateOnSetActive = useCallback(
+  async ({ session, redirectUrl }: { session: SessionResource; redirectUrl?: string }) => {
     const currentTask = session.currentTask;
     if (!currentTask) {
-      return navigate(redirectUrl);
+      return navigate(redirectUrl || afterSignInUrl);
     }
 
     const taskEndpoint = getTaskEndpoint(currentTask);
     const taskNavigationPath = isCombinedFlow ? '/create' + taskEndpoint : taskEndpoint;
 
     return navigate(`/${basePath}${taskNavigationPath}`);
-  };
+  },
+  [navigate, basePath, isCombinedFlow, afterSignInUrl]
+);
packages/types/src/clerk.ts (1)

1208-1229: Document the precedence of navigate over redirectUrl

The JSDoc should explicitly mention that when both navigate and redirectUrl are provided, navigate takes precedence and redirectUrl is ignored.

   /**
    * A custom navigation function to be called just before the session and/or organization is set.
    *
-   * When provided, it takes precedence over the `redirectUrl` parameter for navigation.
+   * When provided, it takes precedence over the `redirectUrl` parameter for navigation.
+   * If both `navigate` and `redirectUrl` are specified, `redirectUrl` will be ignored.
    *
    * @example
    * ```typescript
    * await clerk.setActive({
    *   session,
+   *   redirectUrl: '/dashboard', // This will be ignored
    *   navigate: async ({ session }) => {
    *     const currentTask = session.currentTask;
    *     if (currentTask) {
    *       await router.push(`/onboarding/${currentTask.key}`)
    *       return
    *     }
    *
    *     router.push('/dashboard');
    *   }
    * });
    * ```
    */
   navigate?: SetActiveNavigate;
packages/clerk-js/src/core/clerk.ts (3)

1554-1574: Add JSDoc for new public API: buildTasksUrl

Public APIs must be documented. Add behavior, precedence, and a brief example.

Apply this diff:

+  /**
+   * Builds the URL for the current session task.
+   *
+   * Precedence:
+   * - If a provider-level `taskUrls` override exists for the current task key, that URL is returned.
+   * - Otherwise, returns a default hash-based tasks URL under the SignIn base.
+   *
+   * Returns an empty string when there is no current task.
+   *
+   * @public
+   * @returns {string}
+   * @example
+   * const to = clerk.buildTasksUrl();
+   * if (to) await clerk.navigate(to);
+   */
   public buildTasksUrl(): string {

1666-1672: Add JSDoc for new public API: redirectToTasks

Document behavior and that it no-ops outside the browser.

Apply this diff:

-  public redirectToTasks = async (): Promise<unknown> => {
+  /**
+   * Navigates to the current session task URL, if any.
+   * No-ops on non-browser environments.
+   *
+   * @public
+   * @returns {Promise<unknown>}
+   */
+  public redirectToTasks = async (): Promise<unknown> => {

1201-1356: Tests needed for new after-auth flows and edge cases

Add/extend tests to cover:

  • setActive().navigate precedence vs taskUrls
  • redirectUrl propagation for both hash and path routes
  • error handling when navigate callback throws
  • SSO/Web3 flows navigating to tasks with provider overrides

Do you want me to draft unit/integration tests for these cases (including hash vs query preservation)? I can propose Jest/Vitest test scaffolding aligned with existing suites.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 979ed52 and 2de7d6e.

⛔ Files ignored due to path filters (3)
  • packages/react-router/src/__tests__/__snapshots__/exports.test.ts.snap is excluded by !**/*.snap
  • packages/remix/src/__tests__/__snapshots__/exports.test.ts.snap is excluded by !**/*.snap
  • packages/tanstack-react-start/src/__tests__/__snapshots__/exports.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (50)
  • .changeset/rich-donuts-agree.md (1 hunks)
  • .changeset/warm-rocks-flow.md (1 hunks)
  • integration/tests/session-tasks-sign-in.test.ts (1 hunks)
  • integration/tests/session-tasks-sign-up.test.ts (4 hunks)
  • packages/clerk-js/bundlewatch.config.json (1 hunks)
  • packages/clerk-js/src/core/__tests__/clerk.test.ts (9 hunks)
  • packages/clerk-js/src/core/clerk.ts (21 hunks)
  • packages/clerk-js/src/core/resources/SignIn.ts (1 hunks)
  • packages/clerk-js/src/core/resources/SignUp.ts (1 hunks)
  • packages/clerk-js/src/core/sessionTasks.ts (1 hunks)
  • packages/clerk-js/src/ui/common/redirects.ts (0 hunks)
  • packages/clerk-js/src/ui/common/withRedirect.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/SessionTasks/index.tsx (5 hunks)
  • packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/ChooseOrganizationScreen.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/CreateOrganizationScreen.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/SessionTasks/tasks/withTaskGuard.ts (1 hunks)
  • packages/clerk-js/src/ui/components/SignIn/SignInAccountSwitcher.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorOneAlternativeChannelCodeForm.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwo.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoCodeForm.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignIn/SignInSSOCallback.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/SignIn/SignInStart.tsx (7 hunks)
  • packages/clerk-js/src/ui/components/SignIn/__tests__/handleCombinedFlowTransfer.test.ts (5 hunks)
  • packages/clerk-js/src/ui/components/SignIn/handleCombinedFlowTransfer.ts (4 hunks)
  • packages/clerk-js/src/ui/components/SignIn/index.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignIn/shared.ts (2 hunks)
  • packages/clerk-js/src/ui/components/SignUp/SignUpContinue.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignUp/SignUpEmailLinkCard.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignUp/SignUpSSOCallback.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx (5 hunks)
  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/SignUp/index.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/UserButton/useMultisessionActions.tsx (3 hunks)
  • packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx (2 hunks)
  • packages/clerk-js/src/ui/contexts/components/SignIn.ts (4 hunks)
  • packages/clerk-js/src/ui/contexts/components/SignUp.ts (4 hunks)
  • packages/clerk-js/src/ui/lazyModules/components.ts (1 hunks)
  • packages/clerk-js/src/ui/types.ts (2 hunks)
  • packages/clerk-js/src/utils/componentGuards.ts (1 hunks)
  • packages/nextjs/src/client-boundary/controlComponents.ts (1 hunks)
  • packages/nextjs/src/index.ts (0 hunks)
  • packages/react/src/components/controlComponents.tsx (1 hunks)
  • packages/react/src/components/index.ts (1 hunks)
  • packages/react/src/isomorphicClerk.ts (2 hunks)
  • packages/types/src/clerk.ts (5 hunks)
  • packages/vue/src/components/controlComponents.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • packages/nextjs/src/index.ts
  • packages/clerk-js/src/ui/common/redirects.ts
🚧 Files skipped from review as they are similar to previous changes (37)
  • integration/tests/session-tasks-sign-in.test.ts
  • packages/nextjs/src/client-boundary/controlComponents.ts
  • packages/clerk-js/src/ui/components/SignIn/SignInSSOCallback.tsx
  • packages/clerk-js/src/ui/components/SignUp/SignUpEmailLinkCard.tsx
  • packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/CreateOrganizationScreen.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwo.tsx
  • .changeset/rich-donuts-agree.md
  • packages/clerk-js/src/ui/components/SignIn/tests/handleCombinedFlowTransfer.test.ts
  • packages/clerk-js/src/ui/components/SignIn/shared.ts
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx
  • packages/clerk-js/src/ui/types.ts
  • packages/clerk-js/src/ui/lazyModules/components.ts
  • packages/react/src/components/controlComponents.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInAccountSwitcher.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorOneAlternativeChannelCodeForm.tsx
  • .changeset/warm-rocks-flow.md
  • packages/clerk-js/src/utils/componentGuards.ts
  • packages/react/src/components/index.ts
  • packages/clerk-js/src/ui/components/SignUp/SignUpSSOCallback.tsx
  • packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx
  • packages/clerk-js/src/ui/components/SignUp/SignUpContinue.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoCodeForm.tsx
  • packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/ChooseOrganizationScreen.tsx
  • packages/vue/src/components/controlComponents.ts
  • integration/tests/session-tasks-sign-up.test.ts
  • packages/clerk-js/src/ui/contexts/components/SignUp.ts
  • packages/clerk-js/src/ui/components/SessionTasks/tasks/withTaskGuard.ts
  • packages/clerk-js/src/ui/components/SignIn/SignInStart.tsx
  • packages/clerk-js/src/ui/components/SessionTasks/index.tsx
  • packages/clerk-js/src/core/resources/SignIn.ts
  • packages/clerk-js/src/ui/common/withRedirect.tsx
  • packages/clerk-js/bundlewatch.config.json
  • packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx
  • packages/clerk-js/src/ui/components/SignIn/handleCombinedFlowTransfer.ts
  • packages/clerk-js/src/ui/components/UserButton/useMultisessionActions.tsx
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/core/resources/SignUp.ts
  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx
  • packages/clerk-js/src/ui/contexts/components/SignIn.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/sessionTasks.ts
  • packages/types/src/clerk.ts
  • packages/clerk-js/src/core/__tests__/clerk.test.ts
  • packages/react/src/isomorphicClerk.ts
  • packages/clerk-js/src/ui/components/SignIn/index.tsx
  • packages/clerk-js/src/ui/components/SignUp/index.tsx
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/core/resources/SignUp.ts
  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx
  • packages/clerk-js/src/ui/contexts/components/SignIn.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/sessionTasks.ts
  • packages/types/src/clerk.ts
  • packages/clerk-js/src/core/__tests__/clerk.test.ts
  • packages/react/src/isomorphicClerk.ts
  • packages/clerk-js/src/ui/components/SignIn/index.tsx
  • packages/clerk-js/src/ui/components/SignUp/index.tsx
packages/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/core/resources/SignUp.ts
  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx
  • packages/clerk-js/src/ui/contexts/components/SignIn.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/sessionTasks.ts
  • packages/types/src/clerk.ts
  • packages/clerk-js/src/core/__tests__/clerk.test.ts
  • packages/react/src/isomorphicClerk.ts
  • packages/clerk-js/src/ui/components/SignIn/index.tsx
  • packages/clerk-js/src/ui/components/SignUp/index.tsx
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/core/resources/SignUp.ts
  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx
  • packages/clerk-js/src/ui/contexts/components/SignIn.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/sessionTasks.ts
  • packages/types/src/clerk.ts
  • packages/clerk-js/src/core/__tests__/clerk.test.ts
  • packages/react/src/isomorphicClerk.ts
  • packages/clerk-js/src/ui/components/SignIn/index.tsx
  • packages/clerk-js/src/ui/components/SignUp/index.tsx
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/core/resources/SignUp.ts
  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx
  • packages/clerk-js/src/ui/contexts/components/SignIn.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/sessionTasks.ts
  • packages/types/src/clerk.ts
  • packages/clerk-js/src/core/__tests__/clerk.test.ts
  • packages/react/src/isomorphicClerk.ts
  • packages/clerk-js/src/ui/components/SignIn/index.tsx
  • packages/clerk-js/src/ui/components/SignUp/index.tsx
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/core/resources/SignUp.ts
  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx
  • packages/clerk-js/src/ui/contexts/components/SignIn.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/sessionTasks.ts
  • packages/types/src/clerk.ts
  • packages/clerk-js/src/core/__tests__/clerk.test.ts
  • packages/react/src/isomorphicClerk.ts
  • packages/clerk-js/src/ui/components/SignIn/index.tsx
  • packages/clerk-js/src/ui/components/SignUp/index.tsx
**/*

⚙️ CodeRabbit Configuration File

If there are no tests added or modified as part of the PR, please suggest that tests be added to cover the changes.

Files:

  • packages/clerk-js/src/core/resources/SignUp.ts
  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx
  • packages/clerk-js/src/ui/contexts/components/SignIn.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/sessionTasks.ts
  • packages/types/src/clerk.ts
  • packages/clerk-js/src/core/__tests__/clerk.test.ts
  • packages/react/src/isomorphicClerk.ts
  • packages/clerk-js/src/ui/components/SignIn/index.tsx
  • packages/clerk-js/src/ui/components/SignUp/index.tsx
packages/clerk-js/src/ui/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/clerk-js-ui.mdc)

packages/clerk-js/src/ui/**/*.{ts,tsx}: Element descriptors should always be camelCase
Use element descriptors in UI components to enable consistent theming and styling via appearance.elements
Element descriptors should generate unique, stable CSS classes for theming
Element descriptors should handle state classes (e.g., cl-loading, cl-active, cl-error, cl-open) automatically based on component state
Do not render hard-coded values; all user-facing strings must be localized using provided localization methods
Use the useLocalizations hook and localizationKeys utility for all text and error messages
Use the styled system (sx prop, theme tokens, responsive values) for custom component styling
Use useCardState for card-level state, useFormState for form-level state, and useLoadingStatus for loading states
Always use handleError utility for API errors and use translateError for localized error messages
Use useFormControl for form field state, implement proper validation, and handle loading and error states in forms
Use localization keys for all form labels and placeholders
Use element descriptors for consistent styling and follow the theme token system
Use the Card and FormContainer patterns for consistent UI structure

Files:

  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx
  • packages/clerk-js/src/ui/contexts/components/SignIn.ts
  • packages/clerk-js/src/ui/components/SignIn/index.tsx
  • packages/clerk-js/src/ui/components/SignUp/index.tsx
**/*.{jsx,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

**/*.{jsx,tsx}: Use error boundaries in React components
Minimize re-renders in React components

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components: UserProfile, NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...

Files:

  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx
  • packages/clerk-js/src/ui/components/SignIn/index.tsx
  • packages/clerk-js/src/ui/components/SignUp/index.tsx
**/*.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/react.mdc)

**/*.tsx: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering

Files:

  • packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx
  • packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx
  • packages/clerk-js/src/ui/components/SignIn/index.tsx
  • packages/clerk-js/src/ui/components/SignUp/index.tsx
packages/**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo.mdc)

Unit tests should use Jest or Vitest as the test runner.

Files:

  • packages/clerk-js/src/core/__tests__/clerk.test.ts
packages/{clerk-js,elements,themes}/**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo.mdc)

Visual regression testing should be performed for UI components.

Files:

  • packages/clerk-js/src/core/__tests__/clerk.test.ts
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/typescript.mdc)

**/__tests__/**/*.{ts,tsx}: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces

Files:

  • packages/clerk-js/src/core/__tests__/clerk.test.ts
🧠 Learnings (1)
📚 Learning: 2025-08-08T19:00:08.988Z
Learnt from: LauraBeatris
PR: clerk/javascript#6486
File: packages/clerk-js/src/core/clerk.ts:1303-1344
Timestamp: 2025-08-08T19:00:08.988Z
Learning: In Clerk's navigation system for pending sessions, `taskUrls` (configured at the ClerkProvider level) should take priority over the `navigate` callback (from All-In-One components). This ensures that explicit provider-level configuration overrides component-level navigation logic, providing developers with predictable control over navigation behavior.

Applied to files:

  • packages/clerk-js/src/core/clerk.ts
🧬 Code Graph Analysis (6)
packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx (1)
packages/clerk-js/src/ui/contexts/components/SignIn.ts (1)
  • useSignInContext (38-169)
packages/clerk-js/src/ui/contexts/components/SignIn.ts (7)
packages/types/src/session.ts (1)
  • SessionResource (208-261)
packages/clerk-js/src/ui/types.ts (1)
  • SignInCtx (64-68)
packages/clerk-js/src/ui/router/RouteContext.tsx (1)
  • useRouter (33-39)
packages/clerk-js/src/core/resources/Session.ts (1)
  • currentTask (390-393)
packages/react/src/isomorphicClerk.ts (1)
  • session (672-678)
packages/clerk-js/src/core/sessionTasks.ts (1)
  • getTaskEndpoint (16-16)
packages/clerk-js/src/ui/common/redirects.ts (1)
  • buildRedirectUrl (58-79)
packages/clerk-js/src/core/clerk.ts (8)
packages/clerk-js/src/utils/componentGuards.ts (1)
  • isSignedInAndSingleSessionModeEnabled (9-11)
packages/types/src/clerk.ts (1)
  • SetActiveParams (1185-1230)
packages/react/src/isomorphicClerk.ts (1)
  • session (672-678)
packages/types/src/session.ts (2)
  • SignedInSessionResource (285-285)
  • SessionResource (208-261)
packages/clerk-js/src/core/sessionTasks.ts (3)
  • warnMissingPendingTaskHandlers (55-69)
  • getTaskEndpoint (16-16)
  • navigateIfTaskExists (37-53)
packages/clerk-js/src/utils/url.ts (1)
  • buildURL (84-158)
packages/clerk-js/src/core/resources/Session.ts (1)
  • currentTask (390-393)
packages/clerk-js/src/utils/runtime.ts (1)
  • inBrowser (1-3)
packages/clerk-js/src/core/sessionTasks.ts (4)
packages/types/src/session.ts (1)
  • SessionTask (332-337)
packages/clerk-js/src/utils/url.ts (1)
  • buildURL (84-158)
packages/clerk-js/src/utils/getClerkQueryParam.ts (1)
  • forwardClerkQueryParams (58-70)
packages/clerk-js/src/core/resources/Session.ts (1)
  • currentTask (390-393)
packages/types/src/clerk.ts (1)
packages/types/src/session.ts (1)
  • SessionResource (208-261)
packages/clerk-js/src/core/__tests__/clerk.test.ts (3)
packages/types/src/clerk.ts (1)
  • Clerk (164-886)
packages/clerk-js/src/core/clerk.ts (1)
  • Clerk (193-2878)
packages/types/src/session.ts (1)
  • PendingSessionResource (275-279)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: Integration Tests (tanstack-react-router, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Unit Tests (18, --filter=@clerk/astro --filter=@clerk/backend --filter=@clerk/express --filter=@c...
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Static analysis
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (16)
packages/clerk-js/src/ui/components/SignIn/index.tsx (2)

138-140: LGTM: tasks route exposure under combined flow

Adding the create/tasks route aligns with the new task navigation. Ensure LazySessionTasks handles nested task paths under /tasks/*.

If your router requires wildcards for nested segments (e.g., /tasks/choose-organization), confirm the route matches them. If necessary, adjust:

  • Route path='tasks/*'

17-17: Router import change looks fine

No issues with the router imports; consistent with current usage across the file.

packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx (1)

27-27: Good adoption of navigate-on-setActive

Switching to navigateOnSetActive with afterSignInUrl preserves the new API contract and avoids automatic redirects.

packages/clerk-js/src/ui/components/SignUp/SignUpVerificationCodeForm.tsx (1)

27-27: Good: delegate navigation via navigateOnSetActive

This aligns with the new setActive navigate callback and centralizes route logic in context.

packages/clerk-js/src/core/resources/SignUp.ts (1)

297-297: Behavior change: actionCompleteRedirectUrl now always redirectUrlComplete

This removes the prior conditional behavior. Verify:

  • SSO callback flows still route to the intended task or completion URLs.
  • Any pending-task navigation after SSO continues to work (the PR notes issues here).

Recommend targeted E2E verification for:

  • Social SSO sign-up with a pending task (e.g., choose-organization): confirm redirect lands on the task, and redirectUrl is preserved when completing the task.
  • Non-pending flows: confirm redirectUrlComplete remains honored.

If issues persist, consider deferring to the new central task-navigation helpers in sessionTasks and contexts for consistency.

packages/clerk-js/src/ui/contexts/components/SignIn.ts (2)

123-133: Remove debug statement and unused variable

The debugger statement on line 125 violates ESLint's no-debugger rule and will break production builds. Additionally, taskNavigationPath is computed but never used, causing an ESLint no-unused-vars violation.

 const navigateOnSetActive = async ({ session, redirectUrl }: { session: SessionResource; redirectUrl: string }) => {
-  debugger;
   const currentTask = session.currentTask;
   if (!currentTask) {
     return navigate(redirectUrl);
   }
 
   const taskEndpoint = getTaskEndpoint(currentTask);
-  const taskNavigationPath = isCombinedFlow ? '/create' + taskEndpoint : taskEndpoint;
+  const navigationPath = (isCombinedFlow ? '/create' : '') + taskEndpoint;
 
-  return navigate(`/${basePath + path}`);
+  return navigate(`/${basePath}${navigationPath}`);
 };

Likely an incorrect or invalid review comment.


132-132: path is undefined - will cause runtime error

The variable path is not defined in this scope, which will cause a runtime error when navigating to a task URL. The code should use the computed taskNavigationPath (or navigationPath from the fix above).

-  return navigate(`/${basePath + path}`);
+  return navigate(`/${basePath}${taskNavigationPath}`);

Likely an incorrect or invalid review comment.

packages/react/src/isomorphicClerk.ts (2)

391-398: LGTM! Clean implementation of buildTasksUrl

The implementation correctly follows the established pre-mount queuing pattern used by other build methods, maintaining consistency across the codebase.


1279-1287: LGTM! Consistent implementation of redirectToTasks

The async redirect method correctly follows the established pattern, properly handling both loaded and pre-mount states.

packages/clerk-js/src/core/__tests__/clerk.test.ts (1)

1036-1036: LGTM! Test correctly reflects new task navigation behavior

The expectation properly validates navigation to the task URL using the new navigation pattern.

packages/clerk-js/src/core/clerk.ts (6)

554-561: LGTM: Guarding SignIn in single-session mode is correct

Blocking SignIn when already signed-in and single-session mode is enabled matches expected UX, and the dev-only error helps during integration.


689-695: LGTM: Guarding SignUp in single-session mode is correct

Same rationale as SignIn guard; behavior and dev-only error are appropriate.


1231-1234: Good fix: no more false positives in pending-task warning

Passing the merged source ({ ...this.#options, ...params }) ensures warnMissingPendingTaskHandlers can see taskUrls/navigate.


1266-1271: LGTM: Pending-session cache revalidation guard

Skipping onBeforeSetActive for pending sessions avoids unnecessary unmounts during task navigation.


1305-1309: LGTM: Compute taskUrl from the new session

Using newSession.currentTask respects the session being activated and aligns with provider-level overrides precedence.


2002-2005: LGTM: Centralized fallback to redirectToTasks

Using the new public API here keeps SSO callback logic simple and consistent with task-url precedence.

Comment on lines +2175 to +2185
const setActiveNavigate = async ({ session, redirectUrl }: { session: SessionResource; redirectUrl: string }) => {
if (!session.currentTask) {
await this.navigate(redirectUrl);
return;
}

await navigateIfTaskExists(session, {
baseUrl: displayConfig.signInUrl,
navigate: this.navigate,
});
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Web3 after-auth parity with OAuth: preserve redirectUrl and provider overrides

Mirror OAuth behavior: build the task URL locally, append redirectUrl properly, and respect taskUrls.

Apply this diff:

-    const setActiveNavigate = async ({ session, redirectUrl }: { session: SessionResource; redirectUrl: string }) => {
-      if (!session.currentTask) {
-        await this.navigate(redirectUrl);
-        return;
-      }
-
-      await navigateIfTaskExists(session, {
-        baseUrl: displayConfig.signInUrl,
-        navigate: this.navigate,
-      });
-    };
+    const setActiveNavigate = async ({ session, redirectUrl }: { session: SessionResource; redirectUrl: string }) => {
+      if (!session.currentTask) {
+        await this.navigate(redirectUrl);
+        return;
+      }
+      const customTaskUrl = this.#options.taskUrls?.[session.currentTask.key];
+      let to =
+        customTaskUrl ??
+        (buildURL({ base: displayConfig.signInUrl, hashPath: getTaskEndpoint(session.currentTask) }, { stringify: true }) as string);
+      if (redirectUrl) {
+        const useHash = to.includes('#');
+        const buildOpts: Record<string, unknown> = { base: to };
+        if (useHash) {
+          buildOpts.hashSearchParams = { redirectUrl };
+        } else {
+          buildOpts.searchParams = { redirectUrl };
+        }
+        to = buildURL(buildOpts, { stringify: true }) as string;
+      }
+      await this.navigate(to);
+    };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const setActiveNavigate = async ({ session, redirectUrl }: { session: SessionResource; redirectUrl: string }) => {
if (!session.currentTask) {
await this.navigate(redirectUrl);
return;
}
await navigateIfTaskExists(session, {
baseUrl: displayConfig.signInUrl,
navigate: this.navigate,
});
};
const setActiveNavigate = async ({ session, redirectUrl }: { session: SessionResource; redirectUrl: string }) => {
if (!session.currentTask) {
await this.navigate(redirectUrl);
return;
}
const customTaskUrl = this.#options.taskUrls?.[session.currentTask.key];
let to =
customTaskUrl ??
(buildURL(
{ base: displayConfig.signInUrl, hashPath: getTaskEndpoint(session.currentTask) },
{ stringify: true }
) as string);
if (redirectUrl) {
const useHash = to.includes('#');
const buildOpts: Record<string, unknown> = { base: to };
if (useHash) {
buildOpts.hashSearchParams = { redirectUrl };
} else {
buildOpts.searchParams = { redirectUrl };
}
to = buildURL(buildOpts, { stringify: true }) as string;
}
await this.navigate(to);
};
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/clerk.ts around lines 2175 to 2185, the
setActiveNavigate implementation for Web3 diverges from OAuth: instead of
calling navigateIfTaskExists blindly, build the task URL locally using
session.currentTask.taskUrl or displayConfig.taskUrls/provider overrides, append
the redirectUrl as a query param (properly encoding), and then call
this.navigate with that constructed URL; ensure provider-specific overrides are
honored and that fallback to displayConfig.signInUrl occurs when taskUrl is
missing.

Comment on lines +55 to +60
return setActive({
session: res.createdSessionId,
navigate: async ({ session }) => {
await navigateOnSetActive({ session, redirectUrl: afterSignInUrl });
},
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify navigateOnSetActive respects taskUrls overrides and preserves params

The SignIn context’s navigateOnSetActive (see packages/clerk-js/src/ui/contexts/components/SignIn.ts) builds a task path from INTERNAL_SESSION_TASK_ROUTE_BY_KEY and does not appear to use taskUrls or forward preserved params. That would bypass user-provided overrides and drop important query params.

Run this script to confirm current behavior and surface any missed wiring:

If confirmed, consider:

  • Respecting taskUrls in navigateOnSetActive when present.
  • Forwarding preserved params (e.g., via forwardClerkQueryParams) into the hash for SPA routes.

---

🏁 Script executed:

```shell
#!/bin/bash
# Inspect navigateOnSetActive implementations and taskUrls usage
rg -n "navigateOnSetActive" -A 40 packages/clerk-js/src/ui/contexts/components
echo "----"
rg -n "taskUrls" -A 5 packages/clerk-js/src/ui/contexts/components
echo "----"
rg -n "getTaskEndpoint|INTERNAL_SESSION_TASK_ROUTE_BY_KEY" -A 5 packages/clerk-js/src/ui/contexts/components

Length of output: 20238


Ensure navigateOnSetActive respects custom taskUrls and retains query parameters

Currently in packages/clerk-js/src/ui/contexts/components/SignIn.ts (lines 123–133), navigateOnSetActive ignores any user-provided taskUrls overrides and drops preserved query params when session.currentTask exists. Update it to:

• Check for an override via clerk.__internal_getOption('taskUrls')?.[currentTask.key]
• If present, call navigate with that URL (forwarding queryParams)
• Otherwise build the default path as before, but still wrap it with forwardClerkQueryParams

Locations to update:

  • packages/clerk-js/src/ui/contexts/components/SignIn.ts, function navigateOnSetActive (around line 123)

Suggested diff:

@@ packages/clerk-js/src/ui/contexts/components/SignIn.ts
 const navigateOnSetActive = async ({ session, redirectUrl }) => {
   const currentTask = session.currentTask;
   if (!currentTask) {
     return navigate(redirectUrl);
   }

-  const taskEndpoint = getTaskEndpoint(currentTask);
-  const taskNavigationPath = isCombinedFlow ? '/create' + taskEndpoint : taskEndpoint;
-  return navigate(`/${basePath + taskNavigationPath}`);
+  // Prefer user-provided override
+  const overrideUrl = clerk.__internal_getOption('taskUrls')?.[currentTask.key];
+  if (overrideUrl) {
+    return navigate(forwardClerkQueryParams(overrideUrl, queryParams));
+  }
+
+  // Fallback to default task route, preserving query params
+  const taskEndpoint = getTaskEndpoint(currentTask);
+  const taskPath = isCombinedFlow ? '/create' + taskEndpoint : taskEndpoint;
+  const defaultUrl = `/${basePath + taskPath}`;
+  return navigate(forwardClerkQueryParams(defaultUrl, queryParams));
 };

Be sure to import and use forwardClerkQueryParams and pull in clerk and queryParams from the outer scope.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/clerk-js/src/ui/contexts/components/SignIn.ts around lines 123 to
133, navigateOnSetActive currently ignores user-provided taskUrls overrides and
drops preserved query params when session.currentTask exists; update it to first
check clerk.__internal_getOption('taskUrls')?.[currentTask.key] and if present
call navigate with that override URL while forwarding queryParams (use
forwardClerkQueryParams to attach them), otherwise build the default path as
before but still wrap it with forwardClerkQueryParams; ensure clerk and
queryParams are referenced from the outer scope and import/use
forwardClerkQueryParams in this file.

Comment on lines +46 to +52
handleComplete: () =>
setActive({
session: res.createdSessionId,
navigate: async ({ session }) => {
await navigateOnSetActive({ session, redirectUrl: afterSignUpUrl });
},
}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Ensure navigateOnSetActive honors taskUrls and preserves redirectUrl/query params

The SignUp context’s navigateOnSetActive (see packages/clerk-js/src/ui/contexts/components/SignUp.ts) currently constructs a static /tasks/... path; it may ignore configured taskUrls and drop preserved params. This could regress the PR goal to support ClerkProvider.taskUrls + redirectUrl preservation.

Use this to verify:

If confirmed, update navigateOnSetActive to:

  • Prefer options.taskUrls[currentTask.key] when provided (append redirect_url appropriately).
  • Otherwise build a URL with getTaskEndpoint and forwardClerkQueryParams + redirect_url into hashSearchParams.

---

🏁 Script executed:

```shell
#!/bin/bash
rg -n "navigateOnSetActive" -A 40 packages/clerk-js/src/ui/contexts/components/SignUp.ts
rg -n "taskUrls" -A 5 packages/clerk-js/src/ui/contexts/components/SignUp.ts

Length of output: 3237


Fix navigateOnSetActive to respect taskUrls and preserve redirectUrl/query params

The current implementation in
packages/clerk-js/src/ui/contexts/components/SignUp.ts (lines 118–125) always does:

if (!currentTask) {
  return navigate(redirectUrl);
}
return navigate(`/${basePath}/tasks/${INTERNAL_SESSION_TASK_ROUTE_BY_KEY[currentTask.key]}`);

This ignores any custom options.taskUrls and drops both the incoming redirectUrl and existing Clerk query parameters. To fully support ClerkProvider.taskUrls and URL-param preservation, update navigateOnSetActive to:

  • Prefer options.taskUrls[currentTask.key], appending redirect_url plus the existing Clerk query params (from queryParams).
  • Otherwise fall back to your standard buildRedirectUrl({ routing, baseUrl: signInUrl, authQueryString, path, endpoint: getTaskEndpoint(currentTask), redirectUrl }).
  • Call navigate() with that computed URL instead of the hard-coded /tasks/... route.

For example:

-    return navigate(`/${basePath}/tasks/${INTERNAL_SESSION_TASK_ROUTE_BY_KEY[currentTask.key]}`);
+    const taskUrls = clerk.__internal_getOption('taskUrls');
+    const customTaskUrl = taskUrls?.[currentTask.key];
+    const targetUrl = customTaskUrl
+      ? appendSearchParams(customTaskUrl, { redirect_url: redirectUrl, ...queryParams })
+      : buildRedirectUrl({
+          routing: ctx.routing,
+          baseUrl: signInUrl,
+          authQueryString,
+          path: ctx.path,
+          endpoint: getTaskEndpoint(currentTask),
+          redirectUrl,
+        });
+    return navigate(targetUrl);

This ensures both custom task endpoints and all query params (including your post-signup redirect) are honored.

🤖 Prompt for AI Agents
In packages/clerk-js/src/ui/contexts/components/SignUp.ts around lines 118–125,
navigateOnSetActive currently ignores options.taskUrls and drops redirectUrl and
existing Clerk query params; update it to compute a targetUrl: if currentTask
exists and options.taskUrls[currentTask.key] is defined use that URL as the base
and append redirect_url (redirectUrl) plus the existing Clerk query params from
queryParams; otherwise call buildRedirectUrl({ routing, baseUrl: signInUrl,
authQueryString, path, endpoint: getTaskEndpoint(currentTask), redirectUrl }) to
compute the fallback URL; finally call navigate(targetUrl) with the computed URL
(not the hard-coded /tasks/ route) so custom taskUrls and all query params are
preserved.

@LauraBeatris LauraBeatris merged commit 69498df into main Aug 13, 2025
39 checks passed
@LauraBeatris LauraBeatris deleted the laura/introduce-on-pending-session branch August 13, 2025 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants